import { useVueFlow, Node } from "@vue-flow/core"
import { ref, watch } from "vue"
import { ElMessage } from "element-plus"

/**
 * In a real world scenario you'd want to avoid creating refs in a global scope like this as they might not be cleaned up properly.
 * @type {{draggedType: Ref<string|undefined>, isDragOver: Ref<boolean>, isDragging: Ref<boolean>, sourcePosition: Ref<Position | undefined>}}
 */
const state = {
  /**
   * The type of the node being dragged.
   */
  draggedType: ref(undefined),
  isDragOver: ref(false),
  isDragging: ref(false),
  newNode: ref<Node>()
}

export default function useDragAndDrop() {
  const { draggedType, isDragOver, isDragging, newNode } = state

  const { addNodes, screenToFlowCoordinate, nodes } = useVueFlow()

  watch(isDragging, (dragging) => {
    document.body.style.userSelect = dragging ? "none" : ""
  })

  // 检查节点类型是否已存在
  function checkNodeTypeExists(node: Node): boolean {
    const newNodeType = node.data?.label.split("_")[0]
    return nodes.value.some((existingNode: Node) => {
      if (existingNode.id === "1") return false
      const nodeType = existingNode.data?.label.split("_")[0]
      return nodeType === newNodeType
    })
  }

  function onDragStart(event: DragEvent, type: any, node: Node) {
    if (event.dataTransfer) {
      event.dataTransfer.setData("application/vueflow", type)
      event.dataTransfer.effectAllowed = "move"
    }

    draggedType.value = type
    isDragging.value = true
    newNode.value = node

    document.addEventListener("drop", onDragEnd)
  }

  /**
   * Handles the drag over event.
   *
   * @param {DragEvent} event
   */
  function onDragOver(event: DragEvent) {
    event.preventDefault()

    if (draggedType.value) {
      isDragOver.value = true

      if (event.dataTransfer) {
        event.dataTransfer.dropEffect = "move"
      }
    }
  }

  function onDragLeave() {
    isDragOver.value = false
  }

  function onDragEnd() {
    isDragging.value = false
    isDragOver.value = false
    draggedType.value = undefined
    newNode.value = undefined
    document.removeEventListener("drop", onDragEnd)
  }

  function onDrop(event: DragEvent) {
    event.preventDefault()

    if (typeof newNode.value === "undefined") return

    if (!newNode.value.data.multiple) {
      // 检查节点类型是否已存在
      if (checkNodeTypeExists(newNode.value)) {
        const nodeType = newNode.value.data.label.split("_")[0]
        ElMessage.warning(`${nodeType}已存在，不能重复添加！`)
        onDragEnd()
        return
      }
    }

    const position = screenToFlowCoordinate({
      x: event.clientX,
      y: event.clientY
    })

    newNode.value.position = position

    addNodes([newNode.value])

    onDragEnd()
  }

  return {
    onDragStart,
    onDragOver,
    onDragLeave,
    onDrop,
    isDragOver
  }
}
